// hwinthread.h
#pragma once
#ifndef __HWINTHREAD_H__
#define __HWINTHREAD_H__

#include "hwindef.h"
#include "hwinlog.h"
#include "hwinsynch.h"

namespace harlinn
{
    namespace windows
    {
        namespace threading
        {
            enum class ThreadPriority
            {
                Idle = THREAD_PRIORITY_IDLE,
                Lowest = THREAD_PRIORITY_LOWEST,
                BelowNormal = THREAD_PRIORITY_BELOW_NORMAL,
                Normal = THREAD_PRIORITY_NORMAL,
                AboveNormal = THREAD_PRIORITY_ABOVE_NORMAL,
                Highest = THREAD_PRIORITY_HIGHEST,
                TimeCritical = THREAD_PRIORITY_TIME_CRITICAL,
                BackgroundBegin = THREAD_MODE_BACKGROUND_BEGIN,
                BackgroundEnd = THREAD_MODE_BACKGROUND_END
            };

            class CurrentThreadHandle;
            class ThreadHandle : public WaitableHandle
            {
                friend class CurrentThreadHandle;
                DWORD threadId;
                HWIN_EXPORT static HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,
                                ThreadHandle* pThreadHandle,DWORD dwCreationFlags);

                HWIN_EXPORT static unsigned __stdcall ThreadStart(void* lpThreadParameter);
            public:
                typedef WaitableHandle Base;
                typedef ThreadPriority ThreadPriority_t;
            protected:
                HWIN_EXPORT ThreadHandle(HANDLE theThreadHandle, bool ownsHandle = true);
            public:
                HWIN_EXPORT ThreadHandle(DWORD stackSize = 0, bool stackSizeIsReservation = false);

                HWIN_EXPORT static std::shared_ptr<CurrentThreadHandle> Current();

                HWIN_EXPORT ThreadHandle& Start();
                HWIN_EXPORT DWORD ThreadId() const;

                HWIN_EXPORT ThreadPriority_t ThreadPriority() const;
                HWIN_EXPORT ThreadHandle& SetThreadPriority(ThreadPriority_t theThreadPriority);

                HWIN_EXPORT DWORD Suspend();
                HWIN_EXPORT DWORD Resume();

                HWIN_EXPORT DWORD ExitCode() const;

            protected:
                HWIN_EXPORT virtual DWORD DoOnRun();

            };


            class CurrentThreadData
            {
                friend class ThreadHandle;
                friend class CurrentThreadHandle;
                std::weak_ptr<ThreadHandle> threadHandle;
                DWORD threadId;
            public:
                HWIN_EXPORT CurrentThreadData();
                HWIN_EXPORT ~CurrentThreadData();

                std::shared_ptr<ThreadHandle> ThreadHandle() const
                {
                    return threadHandle.lock();
                }
            };

            class CurrentThreadHandle : public SystemHandle
            {
                friend class ThreadHandle;
                __declspec(thread) static CurrentThreadData* currentThreadData;
            public:
                HWIN_EXPORT static void InitializeThreadData();
                HWIN_EXPORT static void FinalizeThreadData();
            public:
                typedef SystemHandle Base;
                typedef ThreadPriority ThreadPriority_t;

                HWIN_EXPORT CurrentThreadHandle();

                HWIN_EXPORT ThreadPriority_t ThreadPriority() const;
                HWIN_EXPORT CurrentThreadHandle& SetThreadPriority(ThreadPriority_t theThreadPriority);
                HWIN_EXPORT DWORD Suspend();

                HWIN_EXPORT CurrentThreadHandle& Sleep(DWORD milliSeconds);

                HWIN_EXPORT CurrentThreadHandle& Sleep(TimeSpan duration)
                {
                    DWORD millis = DWORD(duration.TotalMilliseconds());
                    return Sleep(millis);
                }

                HWIN_EXPORT bool Sleep(DWORD milliSeconds,bool alertable);

                bool Sleep(TimeSpan duration,bool alertable)
                {
                    DWORD millis = DWORD(duration.TotalMilliseconds());
                    return Sleep(millis, alertable);
                }
                


            };

        };
    };
};

#endif //__HWINTHREAD_H__
